package com.su.lightthings.service

import android.annotation.SuppressLint
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.telephony.PhoneStateListener
import android.telephony.TelephonyManager
import android.util.Log
import androidx.lifecycle.LifecycleService
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.jieli.jl_bt_ota.constant.StateCode
import com.su.lightthings.viewmodel.ConnectViewModel
import com.su.lightthings.base.BaseApplication
import com.su.lightthings.bluetooth.BtUtil
import com.su.lightthings.entity.ConnectedDeviceEntity
import com.su.lightthings.utils.Cons
import com.su.lightthings.utils.MyPhoneStateListener
import com.su.lightthings.utils.SpUtil
import com.su.lightthings.viewmodel.BleViewModel
//import io.objectbox.query.QueryBuilder
import java.util.Timer
import java.util.TimerTask
import java.util.UUID


class BluetoothService : LifecycleService() {

    companion object {
        private const val TAG = "BluetoothService"
        private const val CONNECT_DEVICE_DELAY = 30_000L
        private const val CONNECT_DEVICE_PERIOD = 60_000L
    }

    private var mBinder: MyBinder? = null
    private var mBtAdapter: BluetoothAdapter? = null
    private var deviceAddress: String = ""

    private val bleViewModel = BleViewModel.INSTANCE
    private val telephonyManager by lazy {
        getSystemService(TELEPHONY_SERVICE) as TelephonyManager
    }
    private val phoneStateListener by lazy {
        MyPhoneStateListener(BaseApplication.instance)
    }

    override fun onBind(intent: Intent): IBinder? {
        super.onBind(intent)
        mBinder = MyBinder()
        return mBinder!!
    }

    override fun onCreate() {
        super.onCreate()
        start()
        observer()
        if (XXPermissions.isGranted(this, Permission.READ_PHONE_STATE)) {
            telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        mBinder = null
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
        Log.d(TAG, "onDestroy: 服务退出")
    }

    /**
     * 开启一个前台服务
     */
    private fun start() {
        val channelId = "com.su.lightthings"
        val channel =
            NotificationChannel(channelId, channelId, NotificationManager.IMPORTANCE_DEFAULT)
        val nm = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
        nm?.let {
            if (it.getNotificationChannel(channelId) == null) {//没有创建
                it.createNotificationChannel(channel)//则先创建
            }
        }
        val notification: Notification
        val builder = Notification.Builder(this, channelId).setContentTitle("").setContentText("")
        notification = builder.build()
        startForeground(1, notification)
    }


    @SuppressLint("MissingPermission")
    private fun observer() {
        if (ConnectViewModel.INSTANCE.deviceConnectionMLD.value == null ||
            ConnectViewModel.INSTANCE.deviceConnectionMLD.value?.state == StateCode.CONNECTION_DISCONNECT
        ) {
            connectLastDevice()
        }

        ConnectViewModel.INSTANCE.deviceConnectionMLD.observe(this) {
            Log.d(TAG, "服务中观察到设备连接状态变化: $it")
            when (it.state) {
//                StateCode.CONNECTION_CONNECTED,
//                StateCode.CONNECTION_OK -> {
                Cons.BleConnectState.BIND -> {
                    //已连接
                    Log.d(TAG, "服务中观察到需要设备连接状态变化:连接成功")
                    //终止自动连接任务
                    connectDeviceTask(false)
                    //更新数据库
                    if (SpUtil.getData(Cons.SP.SP_IS_OTA, Cons.OTA.OTA_NONE) as Int != Cons.OTA.OTA_NONE) {
                        //如果当前状态为OTA状态，则不进行数据库更新操作。因为同一个设备在OTA时MAC地址会变。
                        return@observe
                    }
                    val connectDevice = ConnectViewModel.INSTANCE.getConnectedDevice()
                    if (connectDevice != null) {
//                        val deviceBox = ObjectBox.boxStore.boxFor(ConnectedDeviceEntity::class.java)
//                        val device =
//                            deviceBox.query().equal(ConnectedDeviceEntity_.address, connectDevice.address, QueryBuilder.StringOrder.CASE_INSENSITIVE)
//                                .build().findFirst()
//                        if (device != null) {
//                            //数据库中已有该设备，更新数据库该设备最后连接时间
//                            device.lastConnectTimeStamp = System.currentTimeMillis()
//                            deviceBox.put(device)
//                        } else {
//                            //数据库中没有该设备，新增。
//                            val newDevice = ConnectedDeviceEntity(
//                                address = connectDevice.address,
//                                name = connectDevice.name ?: "",
//                                lastConnectTimeStamp = System.currentTimeMillis()
//                            )
//                            deviceBox.put(newDevice)
//                        }
//                        ConnectViewModel.INSTANCE.getHistoryDevice()
                    }
                }

                StateCode.CONNECTION_DISCONNECT,
                StateCode.CONNECTION_FAILED -> {
                    if (BtUtil.isBleEnable()) {
                        ConnectViewModel.INSTANCE.stopScan()
                        connectDeviceTask(true)
                    }
                }
            }
        }

        ConnectViewModel.INSTANCE.bluetoothStateMLD.observe(this) {
            Log.d(TAG, "服务中观察到蓝牙开关状态改变:$it")
            if (it) {
                connectLastDevice()
            }
        }
    }


    /**
     * 自动重连最后连接的设备
     * 未连接状态下，每隔一分钟发起一次重连。
     * 第一次间隔30秒再启动该任务，防止是主动断开的。
     */
    private var timer: Timer? = null
    private var timerTask: TimerTask? = null
    private var isTimerTaskWorking = false
    private fun connectDeviceTask(b: Boolean) {

        if (b && isTimerTaskWorking) return

        isTimerTaskWorking = b

        if (timer != null) {
            timer!!.cancel();
            timer = null;
        }
        if (timerTask != null) {
            timerTask!!.cancel();
            timerTask = null;
        }
        if (b) {
            timer = Timer()
            timerTask = object : TimerTask() {
                override fun run() {
                    // Check if we've reached the end of the logMessages
                    if (!ConnectViewModel.INSTANCE.isConnected() && !ConnectViewModel.INSTANCE.isConnecting()) {
                        Log.d(TAG, "定时任务：连接上次的设备")
                        val lastAddress: String = SpUtil.getData(Cons.SP.SP_DEVICE_ADDRESS, "") as String
                        if (lastAddress != "") {
                            ConnectViewModel.INSTANCE.connectingDeviceAddress = lastAddress
                            connectLastDevice()
                        }
                    } else {
                        Log.d(TAG, "定时任务：当前有设备已经连接")
                    }
                }
            }
            Log.d(TAG, "执行定时连接任务")
            timer?.scheduleAtFixedRate(timerTask, CONNECT_DEVICE_DELAY, CONNECT_DEVICE_PERIOD)
        }
    }

    private fun connectLastDevice() {
        if ((SpUtil.getData(Cons.SP.SP_IS_OTA, Cons.OTA.OTA_NONE) as Int) != Cons.OTA.OTA_NONE) {
            //当前状态为OTA状态
            Log.d(TAG, "当前状态为OTA状态")
            return
        }
        val lastAddress: String = SpUtil.getData(Cons.SP.SP_DEVICE_ADDRESS, "") as String
        Log.d(TAG, "最后连接的设备: $lastAddress")
        if (lastAddress != "") {
            Log.d(TAG, "最后连接的设备不为空")
            ConnectViewModel.INSTANCE.connectBtDevice(lastAddress)
        }
    }

    inner class MyBinder : Binder() {

        /**
         * 开始扫描
         */
        fun startScanBle() {
            BtUtil.startScan()
        }

        /**
         * 停止扫描
         */
        fun stopScanBle() {
            BtUtil.stopScan()
        }


        /**
         * 连接设备：通过BLE设备进行连接
         * @param device BLE设备
         */
        fun connectBle(device: BluetoothDevice) {
            BtUtil.connectBle(device)
        }

        /**
         * 发起绑定ble设备
         * Android原生方法
         * @param address 要绑定的ble设备地址
         */
        fun bondDevice(mBtAdapter: BluetoothAdapter?, address: String): Boolean? {
            val bondDevices = mBtAdapter?.getRemoteDevice(address)
            val b = bondDevices?.createBond()
            Log.d(TAG, "绑定结果: $b")
            return b
        }

        /**
         * 断开连接
         */
        fun disconnect() {
            ConnectViewModel.INSTANCE.getConnectedDevice()?.let { BtUtil.disconnect(it) }
        }

        /**
         * 发送数据
         */
        fun write(
            data: ByteArray
        ): Boolean {
//            return connectedDevice?.let { BtUtil.write(it, data, writeCallback) } ?: false
            return ConnectViewModel.INSTANCE.getConnectedDevice()
                ?.let { BtUtil.write(it, data) } == true
        }

        /**
         * 发送数据
         */
        fun write(
            serviceUUID: UUID,
            characteristicUUID: UUID,
            data: ByteArray,
        ): Boolean {
//            return connectedDevice?.let { BtUtil.write(it, data, writeCallback) } ?: false
            return ConnectViewModel.INSTANCE.getConnectedDevice()
                ?.let { BtUtil.write(it, serviceUUID, characteristicUUID, data) } == true
        }

        /**
         * 终止BLE监听
         */
        fun disableBLEDeviceNotification(type: Int) {
            return BtUtil.disableBLEDeviceNotification(type)
        }


        /**
         * 开启BLE监听
         */
        fun enableBLEDeviceNotification(type: Int) {
            return BtUtil.enableBLEDeviceNotification(type)
        }

        /**
         * 发送数据
         */
        fun write(
            device: BluetoothDevice,
            data: ByteArray
        ): Boolean {
            return BtUtil.write(device, data)
        }


    }

}